/**
Copyright [2008] [Julian Gamble] 

Licensed under the Apache License, Version 2.0 (the "License"); 
you may not use this file except in compliance with the License. 
You may obtain a copy of the License at 

	http://www.apache.org/licenses/LICENSE-2.0 
	
Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
See the License for the specific language governing permissions and 
limitations under the License. 
 **/
package aerith.swing;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.plaf.basic.BasicButtonUI;

import org.jdesktop.animation.timing.Animator;
import org.jdesktop.animation.timing.TimingTarget;

import aerith.GraphicsUtil;

public class AerithActionButton extends JButton {

	/**
	 * 
	 */
	private static final long serialVersionUID = -5426198605802559272L;
	private float shadowOffsetX;
	private float shadowOffsetY;

	private Color shadowColor = Color.decode("#000000");
	private int shadowDirection = 60;

	private Image mainButton, mainButtonPressed, normalButton,
			normalButtonPressed, buttonHighlight;
	private int shadowDistance = 1;
	private Insets sourceInsets = new Insets(6, 7, 6, 8);
	private Dimension buttonDimension = new Dimension(16, 35);
	private Color buttonForeground = Color.decode("#FFFFFF");
	private Font buttonFont = new Font("Arial", Font.BOLD, 22);

	private float ghostValue;

	private boolean main = false;

	public AerithActionButton(String text) {
		this();
		setText(text);
	}

	public AerithActionButton(Action a) {
		this();
		setAction(a);
	}

	public AerithActionButton() {

		loadImages();

		computeShadow();

		addMouseListener(new HiglightHandler());

		setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
		setForeground(buttonForeground);
		setFont(buttonFont);
		setContentAreaFilled(false);
		setBorderPainted(false);
		setFocusable(false);

		// Hacky? Hacky!
		setUI(new BasicButtonUI() {
			@Override
			public Dimension getMinimumSize(JComponent c) {
				return getPreferredSize(c);
			}

			@Override
			public Dimension getMaximumSize(JComponent c) {
				return getPreferredSize(c);
			}

			@Override
			public Dimension getPreferredSize(JComponent c) {
				Insets insets = c.getInsets();
				Dimension d = new Dimension(buttonDimension);
				d.width += insets.left + insets.right;
				d.height += insets.top + insets.bottom;
				return d;
			}
		});
	}

	private void loadImages() {
		mainButton = loadImage("/resources/photos/button-main.png");
		mainButtonPressed = loadImage("/resources/photos/button-main-pressed.png");
		normalButton = loadImage("/resources/photos/button-normal.png");
		normalButtonPressed = loadImage("/resources/photos/button-normal-pressed.png");
		buttonHighlight = loadImage("/resources/photos/header-halo.png");
	}

	private Image loadImage(String resourcePath) {
		java.net.URL imageurl = this.getClass().getResource(resourcePath);
		Image result = null;
		try {
			result = javax.imageio.ImageIO.read(imageurl);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

	public void setMain(boolean main) {
		boolean old = isMain();
		this.main = main;
		firePropertyChange("main", old, isMain());
	}

	public boolean isMain() {
		return main;
	}

	private void computeShadow() {
		double rads = Math.toRadians(shadowDirection);
		shadowOffsetX = (float) Math.cos(rads) * shadowDistance;
		shadowOffsetY = (float) Math.sin(rads) * shadowDistance;
	}

	private Image getImage(boolean armed) {
		if (isMain()) {
			return armed ? mainButtonPressed : mainButton;
		} else {
			return armed ? normalButtonPressed : normalButton;
		}
	}

	@Override
	protected void paintComponent(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);

		ButtonModel m = getModel();
		Insets insets = getInsets();

		int width = getWidth() - insets.left - insets.right;
		int height = getHeight() - insets.top - insets.bottom;

		GraphicsUtil.tileStretchPaint(g2, this, (BufferedImage) getImage(m
				.isArmed()), sourceInsets);

		if (ghostValue > 0.0f) {
			g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
					RenderingHints.VALUE_INTERPOLATION_BILINEAR);

			float alphaValue = ghostValue;
			Composite composite = g2.getComposite();
			if (composite instanceof AlphaComposite) {
				alphaValue *= ((AlphaComposite) composite).getAlpha();
			}

			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
					alphaValue));

			g2.drawImage(buttonHighlight, insets.left + 2, insets.top + 2,
					width - 4, height - 4, null);
			g2.setComposite(composite);
		}

		FontMetrics fm = getFontMetrics(getFont());
		TextLayout layout = new TextLayout(getText(), getFont(), g2
				.getFontRenderContext());
		Rectangle2D bounds = layout.getBounds();

		int x = (int) (getWidth() - insets.left - insets.right - bounds
				.getWidth()) / 2;
		//x -= 2;
		int y = (getHeight() - insets.top - insets.bottom - fm.getMaxAscent() - fm
				.getMaxDescent()) / 2;
		y += fm.getAscent() - 1;

		if (m.isArmed()) {
			x += 1;
			y += 1;
		}

		g2.setColor(shadowColor);
		layout.draw(g2, x + (int) Math.ceil(shadowOffsetX), y
				+ (int) Math.ceil(shadowOffsetY));
		g2.setColor(getForeground());
		layout.draw(g2, x, y);
	}

	private final class HiglightHandler extends MouseAdapter {
		private Animator timer;

		@Override
		public void mouseEntered(MouseEvent e) {
			if (timer != null && timer.isRunning()) {
				timer.stop();
			}
			timer = new Animator(300, new AnimateGhost(true));
			timer.start();
		}

		@Override
		public void mouseExited(MouseEvent e) {
			if (timer != null && timer.isRunning()) {
				timer.stop();
			}
			timer = new Animator(300, new AnimateGhost(false));
			timer.start();
		}
	}

	private final class AnimateGhost implements TimingTarget {
		private boolean forward;
		private float oldValue;

		AnimateGhost(boolean forward) {
			this.forward = forward;
			oldValue = ghostValue;
		}

		public void timingEvent(float fraction) {
			ghostValue = oldValue + fraction * (forward ? 1.0f : -1.0f);

			if (ghostValue > 1.0f) {
				ghostValue = 1.0f;
			} else if (ghostValue < 0.0f) {
				ghostValue = 0.0f;
			}

			repaint();
		}

		public void begin() {
		}

		public void end() {
		}

		public void repeat() {
		}
	}
}
